﻿//TODO: Test, Trajkovic (4 Neighbours)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Corner detector
    /// </summary>
    public class Trajkovic : BaseForeBackgroundColorFilter, ICornerFinder
    {
        protected List<Point> m_aPoint = new List<Point>();
        protected bool m_bIntegrate = true;

        /// <summary>
        /// Initializes a new instance of the <see cref="Trajkovic"/> class.
        /// </summary>
        public Trajkovic()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Trajkovic"/> class.
        /// </summary>
        /// <param name="_bIntegrate">if set to <c>true</c> [_b integrate].</param>
        public Trajkovic(bool _bIntegrate)
        {
            m_bIntegrate = _bIntegrate;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Trajkovic"/> class.
        /// </summary>
        /// <param name="_trajkovic">The _trajkovic.</param>
        internal Trajkovic(Trajkovic _trajkovic)
        {
            this.m_bIntegrate = _trajkovic.m_bIntegrate;
            this.UseOnly4Neighbours = _trajkovic.UseOnly4Neighbours;
        }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="Trajkovic"/> is integrate.
        /// </summary>
        /// <value><c>true</c> if integrate; otherwise, <c>false</c>.</value>
        public bool Integrate
        {
            get { return m_bIntegrate; }
            set { m_bIntegrate = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether [use only4 neighbours].
        /// </summary>
        /// <value><c>true</c> if [use only4 neighbours]; otherwise, <c>false</c>.</value>
        protected bool UseOnly4Neighbours
        {
            get { return this.m_NEIGHBOUR == NEIGHBOUR.FOUR; }
            set { m_NEIGHBOUR = value ? NEIGHBOUR.FOUR : NEIGHBOUR.EIGHT; }
        }

        /// <summary>
        /// Gets the points
        /// </summary>
        public List<Point> Points
        {
            get { return m_aPoint; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmapCloned = (UnsafeBitmap)_bitmap.Clone();
            UnsafeBitmap bitmap = _bitmap;
            int nHeight = bitmapCloned.Height;
            int nWidth = bitmapCloned.Width;

            int y = 0;
            int x = 0;

            Color color = Color.Transparent;

            float[] nLuminance = new float[8];

            float[] nResult = new float[4];

            float[,] aCornernessMeasure = new float[nWidth, nHeight];

            for (y = 1; y < nHeight-1; y++)
            {
                for (x = 1; x < nWidth - 1; x++)
                {
                    nLuminance[0] = ColorFunctions.GetLuminance(bitmapCloned.GetPixel(x - 1, y - 1));
                    nLuminance[1] = ColorFunctions.GetLuminance(bitmapCloned.GetPixel(x + 1, y + 1));
                    
                    nLuminance[2] = ColorFunctions.GetLuminance(bitmapCloned.GetPixel(x + 1, y - 1));
                    nLuminance[3] = ColorFunctions.GetLuminance(bitmapCloned.GetPixel(x - 1, y + 1));
                    
                    nLuminance[4] = ColorFunctions.GetLuminance(bitmapCloned.GetPixel(x+1, y));
                    nLuminance[5] = ColorFunctions.GetLuminance(bitmapCloned.GetPixel(x-1, y));
                    
                    nLuminance[6] = ColorFunctions.GetLuminance(bitmapCloned.GetPixel(x, y+1));
                    nLuminance[7] = ColorFunctions.GetLuminance(bitmapCloned.GetPixel(x, y-1));

                    color = bitmapCloned.GetPixel(x, y);
                    float nC = ColorFunctions.GetLuminance(color);

                    //Part 1 
                    float p1 = (nLuminance[0] - nC);
                    float p2 = (nLuminance[1] - nC);

                    nResult[0] = p1 * p1 + p2 * p2;

                    p1 = (nLuminance[2] - nC);
                    p2 = (nLuminance[3] - nC);
                    nResult[1] = p1 * p1 + p2 * p2;

                    //Part 2
                    p1 = (nLuminance[4] - nC);
                    p2 = (nLuminance[5] - nC);
                    nResult[2] = p1 * p1 + p2 * p2;

                    p1 = (nLuminance[6] - nC);
                    p2 = (nLuminance[7] - nC);
                    nResult[3] = p1 * p1 + p2 * p2;

                    float n1 = Math.Min(nResult[0], nResult[1]);
                    float n2 = Math.Min(nResult[2], nResult[3]);

                    bool bIsEdge = n1 == n2 && n1 > 8;
                    if (m_bIntegrate)
                    {
                        if (bIsEdge)
                        {
                            bitmap.SetPixel(x, y, m_ColorForeground);
                        }
                    }
                    else
                    {
                        bitmap.SetPixel(x, y, bIsEdge ? m_ColorForeground : m_ColorBackground);
                    }
                }
            }

            bitmapCloned.Dispose();
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Trajkovic(this);
        }
    }
}
